#ifndef _PLC_ABI_H_
#define _PLC_ABI_H_


#include <stdint.h>

#ifdef ARDUINO

#include <Arduino.h>

#endif

//#include "plc_rte_abi.h"
//#include "iec_app.h"
typedef unsigned short u16;
typedef unsigned char u8;
//typedef unsigned char bool;
typedef unsigned long long u64;

#ifdef __cplusplus
extern "C"
{
#endif
#define PLC_LOC_CONCAT(a, b) a##b

#define PLC_LT_I 0
#define PLC_LT_M 1
#define PLC_LT_Q 2

#define PLC_LOC_TYPE(a) PLC_LOC_CONCAT(PLC_LT_, a)

#define PLC_LSZ_X 1
#define PLC_LSZ_B 1
#define PLC_LSZ_W 2
#define PLC_LSZ_D 4
#define PLC_LSZ_L 8

#define PLC_LOC_SIZE(a) PLC_LOC_CONCAT(PLC_LSZ_, a)
typedef struct _plc_loc_dsc_t plc_loc_dsc_t;

struct _plc_loc_dsc_t {
    void *v_buf;
    u8 v_type;
    u8 v_size;
    u16 a_size;
    const uint32_t *a_data;
    u16 proto;
};
typedef struct {
    uint32_t size_dbgvardsc;
    const void *dbgvardsc;
} plc_data_t;

typedef const plc_loc_dsc_t *plc_loc_tbl_t;

typedef void (*app_fp_t)();

typedef struct {
    uint32_t *sstart;        //链接后的启动地址
    app_fp_t entry;     //plc入口,仅链接用
    uint32_t *data_loadaddr; //数据区(带初始值的变量)加载地址
    uint32_t *data_start;    //数据区起始地址
    uint32_t *data_end;      //数据区结束地址
    uint32_t *bss_end;       //中间变量区结束地址,起始地址跟随数据区
    app_fp_t *pa_start; //初始化函数
    app_fp_t *pa_end;
    app_fp_t *ia_start;
    app_fp_t *ia_end;
    app_fp_t *fia_start;
    app_fp_t *fia_end;

    //RTE Version control
    uint32_t rte_ver_major;
    uint32_t rte_ver_minor;
    uint32_t rte_ver_patch;

    //Hardware ID
    const char *hw_id;

    //IO manager data
    plc_loc_tbl_t *l_tab; //Location table
    u16 l_sz;             //Location table size

    //Control instance of PLC_ID
    const char *check_id;
    //App interface
    const char *id;

    const char *app_name; //应用程序名称
    uint32_t buildnumber;      //应用程序构建编号

    int (*start)(const void *); //plc启动函数 ,plc_rte_abi_t

    int (*stop)(); //plc停止

    void (*run)(); //plc运行,每周期调用一次

    void (*config_init)(); //plc初始化

    void (*dbg_resume)(); //debug启动

    void (*dbg_suspend)(int); //debug挂起

    int (*dbg_data_get)(uint32_t *, uint32_t *, void **); //读取debug数据

    void (*dbg_data_free)(); //释放debug数据

    void (*dbg_vars_reset)(u8); //复位debug变量

    void (*dbg_var_register)(uint32_t); //注册debug变量

    void (*dbg_set_force)(uint32_t, void *); //变量强制

    uint32_t (*GetRetainSize)(); //获取retain大小

    void (*event)(uint32_t state, int value);

    plc_data_t *data;
    uint32_t var_size;

} plc_app_abi_t;

extern const plc_app_abi_t plc_app;
extern plc_app_abi_t *plc_abi;

#define LOG_LEVELS 4
#define LOG_CRITICAL 0
#define LOG_WARNING 1
#define LOG_INFO 2
#define LOG_DEBUG 3
int plc_is_valid(const void *plc_curr_app);

#ifdef __cplusplus
}
#endif
#endif // _PLC_ABI_H_
